package telex;
/*
 * Sentence.java
 *
 * Copyright (c) 2007-2008 Colin Bayer, Douglas Downey, Oren Etzioni,
 *   University of Washington Computer Science and Engineering
 * 
 * See the file "COPYING" in the root directory of this distribution for
 * full licensing information.
 */

import java.io.IOException;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;

import com.aliasi.chunk.Chunk;
import com.aliasi.chunk.Chunking;
import com.aliasi.tokenizer.TokenChunker;
import com.aliasi.tokenizer.Tokenizer;
import com.aliasi.tokenizer.TokenizerFactory;
import java.util.List;

public class Sentence {
	
	public Sentence(String[] aWords) {
		mWords = aWords.clone();
		mIsInNamedEntity = new boolean[aWords.length];
		for (int i = 0; i < mWords.length; i++) {
			mIsInNamedEntity[i] = false;
		}
	}
	
	public Sentence(String[] aWords, boolean[] aIsInNamedEntity) {
		if (aWords.length != aIsInNamedEntity.length) throw new IllegalArgumentException();
		mWords = aWords.clone();
		mIsInNamedEntity = aIsInNamedEntity.clone();
	}

	public Sentence(String aSentence) throws IOException {
		if (mTzr == null) {
			mTzr = OpenNLPProvider.createTokenizer();
		}
                /*
		Chunking ch = new TokenChunker(mTzr).chunk(aSentence);
		int index = 0;
		mWords = new String[ch.chunkSet().size()];
		for ( Chunk c : ch.chunkSet() ) {
			mWords[index++] = ch.charSequence().subSequence(c.start(),c.end()).toString();
		}*/
                char[] cs = new char[aSentence.length()];
                aSentence.getChars(0, aSentence.length(), cs, 0);
                Tokenizer tok = mTzr.tokenizer(cs, 0, cs.length);
                List<String> whiteList = new ArrayList<String>();
                List<String> tokenList = new ArrayList<String>();
                while(true){
                    String whiteSpace = tok.nextWhitespace();
                    whiteList.add(whiteSpace);
                    String token = tok.nextToken();
                    if(token == null)
                        break;
                    tokenList.add(token);
                }
                mWords = tokenList.<String>toArray(new String[tokenList.size()]);
                mWhitespaces = whiteList.<String>toArray(new String[whiteList.size()]);
		mIsInNamedEntity = new boolean[mWords.length];
		for (int i = 0; i < mWords.length; i++) {
			mIsInNamedEntity[i] = false;
		}
	}
	
	public boolean isInNamedEntity(int aIdx) {
		if (aIdx < 0 || aIdx > mWords.length) throw new IllegalArgumentException();		
		return mIsInNamedEntity[aIdx];
	}
	
	public void setInNamedEntity(int aIdx) {
		if (aIdx < 0 || aIdx > mWords.length) throw new IllegalArgumentException();
		mIsInNamedEntity[aIdx] = true;
	}

	public void clearInNamedEntity(int aIdx) {
		if (aIdx < 0 || aIdx > mWords.length) throw new IllegalArgumentException();
		mIsInNamedEntity[aIdx] = false;
	}
	
	public String getWord(int aIdx) {
		if (aIdx < 0 || aIdx > mWords.length) return null;
		return mWords[aIdx];
	}
	
	public String[] getWordSpan(int aLo, int aHi) {
		if (aLo < 0 || aHi > mWords.length || aHi <= aLo) return null;
		String[] wds = new String[aHi - aLo];
		System.arraycopy(mWords, aLo, wds, 0, aHi - aLo);	
		return wds;
	}
	
	public static class EntityRec {
		private EntityRec() { parent = null; idx_lo = idx_hi = -1; }
		private EntityRec(Sentence aParent, int aLo, int aHi)
			{ parent = aParent; idx_lo = aLo; idx_hi = aHi; } 
		public String[] getWords() { return parent.getWordSpan(idx_lo, idx_hi); }
		public int getStartIndex() { return idx_lo; }
		public int getEndIndex() { return idx_hi; }
		private Sentence parent;
		private int idx_lo, idx_hi;
	}
	
	public EntityRec[] getNamedEntities() {
            //ent_list irá ter em cada posição os indices da sequência de nomes
		ArrayList<EntityRec> ent_list = new ArrayList<EntityRec>();
		ArrayList<String> this_ent = new ArrayList<String>();
		int idx = -1;
		for (int i = 0; i < mWords.length; i++) {
                    //condição para o caso de dois nomes seguidos
			if (isInNamedEntity(i)) {
				if (idx < 0) idx = i;
				this_ent.add(mWords[i]);
			} else if (!this_ent.isEmpty()) {
				ent_list.add(new EntityRec(this, idx, i));
				this_ent.clear();
				idx = -1;
			}
		}
		return ent_list.toArray(new EntityRec[0]);
	}
	
	public EntityRec merge(EntityRec aLeft, EntityRec aRight, boolean aMark) {
		if (aLeft.parent != this || aRight.parent != this) return null;	
		EntityRec rv = new EntityRec(this, aLeft.idx_lo, aRight.idx_hi);
		if (aMark) {
			for (int i = aLeft.idx_lo; i < aRight.idx_hi; i++) setInNamedEntity(i);
		}
		return rv;
	}

	public int length() {
		return mWords.length;
	}
	
	/*public String toString() {
		String s = "";
		for (int i = 0; i < mWords.length; i++) {
			s += mWords[i] + "||" + mBelowDeltaThresholds[i] + "||" + mAboveDeltaThresholds[i];
			if (i != mWords.length - 1) s += " ";
		}
		return s;
	}*/
	
	public String toString() {
		boolean last_in_ent = false, this_in_ent;
		String s = "";
                StringBuilder sb = new StringBuilder();
                for(int i = 0; i < mWords.length; i++){
                    this_in_ent = isInNamedEntity(i);
                    if(!last_in_ent || this_in_ent)
                        sb.append(mWhitespaces[i]);
                    if (this_in_ent && !last_in_ent) {
			sb.append("<chunk>");
                    } else if (!this_in_ent && last_in_ent) {
                                sb.append("</chunk>");
                                sb.append(mWhitespaces[i]);
                            }
                    sb.append(mWords[i]);
                    if(this_in_ent && i == mWords.length - 1)
                        sb.append("</chunk>");
                    last_in_ent = this_in_ent;
                }
		/*for (int i = 0; i < mWords.length; i++) {
			this_in_ent = isInNamedEntity(i);
			if (this_in_ent && !last_in_ent) {
				s += "<E> ";
			} else if (!this_in_ent && last_in_ent) {
				s += "</E> ";
			}
			s += mWords[i];
			if (i != mWords.length - 1) s += " ";
			else if (this_in_ent) s += " </E>";
			last_in_ent = this_in_ent;
		}*/
                s = sb.toString();
		return s;
	}
	
	private String[] mWords;
        private String[] mWhitespaces;

	/*
	 * mBelowDeltaThresholds[i] measures (for the first word in a sentence) the maximum
	 * delta at which the word is considered to not be part of a named entity, and
	 * (for all other words) the maximum tau at which the word is considered to
	 * be part of a named entity, if the first word of the sentence is accepted
	 * as a named entity constituent based on the current value of delta.
	 * 
	 * mAboveDeltaThresholds[i] is unused for the first word in a sentence, and (for all
	 * other words) measures the maximum tau at which the word is considered to
	 * be part of a named entity if the first word of the sentence is rejected
	 * as a named entity constituent based on the current value of delta.
	 */
	public double[] mBelowDeltaThresholds;
	public double[] mAboveDeltaThresholds;
	public boolean[] mIsInNamedEntity;
	private static TokenizerFactory mTzr;
	
	/*private boolean isFirstInNamedEntity(double aDelta) {
		return (aDelta <= mBelowDeltaThresholds[0]);
	}
	
	private boolean isInNamedEntity(int aIdx, double aDelta, double aTau) {
		if (aIdx < 0 || aIdx >= mWords.length) return false;
		boolean delta_passed = isFirstInNamedEntity(aDelta);
		if (aIdx == 0) return delta_passed;
		else {
			if (delta_passed && aTau <= mBelowDeltaThresholds[aIdx]) return true;
			else if (delta_passed) return false;
			else if (aTau <= mAboveDeltaThresholds[aIdx]) return true;
			else return false;
		}
	}*/

	public static void main(String[] aArgs) {
		System.out.println("telex: Sentence test");
		if (aArgs.length < 1) {
			System.out.println("usage: java Sentence [base of OpenNLP models/ directory]");
			return;
		}
		OpenNLPProvider.setTokenizerModelPath(aArgs[0] + "/models/tokenize/EnglishTok.bin.gz");
		BufferedReader s_r = new BufferedReader(new InputStreamReader(System.in));
		try {
			while (true) {
				String l = s_r.readLine();
				if (l == null) break;
				Sentence s = new Sentence(l);
				System.out.println(s);
			}
		} catch (IOException e) {
			System.out.println("Read loop terminated with exception: " + e);
		}	
	}

}